package com.alks.function.service.impl.stockdept.pcfactorystockquery;

import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import com.alks.common.aop.AutoPageAop;
import com.alks.common.data.thread.UserIdThread;
import com.alks.common.service.RedisService;
import com.alks.common.utils.DateUtils;
import com.alks.common.utils.beanutils.ArrayUtils;
import com.alks.common.utils.beanutils.BeanUtil;
import com.alks.common.utils.beanutils.ObjectUtils;
import com.alks.common.utils.excelUtils.ExcelPoiUtils;
import com.alks.common.utils.excelUtils.ExcelUtils;
import com.alks.entity.data.entity.*;
import com.alks.entity.data.response.ResponseInfo;
import com.alks.entity.exception.ServiceErrorException;
import com.alks.function.data.dto.chengKong.cost.PcStitchProdDetailDto2;
import com.alks.function.data.dto.chengKong.produce.PcCodeAndStitchDto;
import com.alks.function.data.dto.chengKong.produce.PcLotDetailDto2;
import com.alks.function.data.dto.finance.fincons.InventoryPaymentDetailsDto;
import com.alks.function.data.dto.pcfactoryquery.PcStitchDetailDto;
import com.alks.function.data.dto.pcfactoryquery.PcStitchStockDetailDto;
import com.alks.function.data.dto.stockdept.pcfactorystockwork.StitchDetailDto;
import com.alks.function.data.request.chengKong.PcStitchProdDetailRequest;
import com.alks.function.data.request.factoryquery.StitchStockRequest;
import com.alks.function.data.request.finance.fincons.PcStitchDetailAttachRequest;
import com.alks.function.data.request.stockdept.pcfactorystockwork.PcCodeRequest;
import com.alks.function.data.request.stockdept.pcfactorystockwork.StitchIORequest;
import com.alks.function.mapper.SdUserMapper;
import com.alks.function.mapper.chengKong.PcLotHeadMapper;
import com.alks.function.mapper.chengKong.PcStitchProdDetailMapper;
import com.alks.function.mapper.finance.fincons.SewingProductionDataMapper;
import com.alks.function.mapper.pcfactoryquery.FT_QR_PcStitchDetailAttachMapper;
import com.alks.function.mapper.pcfactoryquery.FT_QR_PcStitchDetailMapper;
import com.alks.function.mapper.pcfactoryquery.FT_QR_PcStitchFrozenMapper;
import com.alks.function.mapper.pcfactoryquery.FT_QR_PcStitchProdDetailMapper;
import com.alks.function.mapper.stockdept.pcfactorystockquery.SD_SQ_PcLotDetailMapper;
import com.alks.function.service.stockdept.pcfactorystockquery.IStitchIOService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.jdbc.UncategorizedSQLException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.alks.entity.data.enums.ResultCodeEnum.*;

@Service
@Slf4j
@RequiredArgsConstructor
public class StitchIOServiceImpl extends ServiceImpl<FT_QR_PcStitchDetailMapper, PcStitchDetail> implements IStitchIOService {
    private final FT_QR_PcStitchDetailMapper detailMapper;
    private final PcLotHeadMapper lotHeadMapper;
    private final SD_SQ_PcLotDetailMapper lotDetailMapper;
    private final RedisService redisService;
    private final FT_QR_PcStitchProdDetailMapper prodDetailMapper;
    private final FT_QR_PcStitchDetailAttachMapper attachMapper;
    private final PcLotHeadMapper pcLotHeadMapper;
    private final FT_QR_PcStitchDetailAttachMapper detailAttachMapper;
    private final RedisTemplate redisTemplate;
    private final PcStitchProdDetailMapper pcStitchProdDetailMapper;
    private final SewingProductionDataMapper sewingProductionDataMapper;
    private final  SdUserMapper sdUserMapper;

    private final FT_QR_PcStitchFrozenMapper pcStitchFrozenMapper;


    @Override
    public ResponseInfo getStitchIOQuery(String lotNo) {
        /*指令判空*/
        if (lotNo==null||lotNo.isEmpty()){
            return ResponseInfo.error("指令不能为空",IN_IS_EMPTY.getCode());
        }
        /*获取数据*/
        List<PcStitchDetail> in = lambdaQuery().eq(PcStitchDetail::getLotNo, lotNo)
                .eq(PcStitchDetail::getSlipType, "I")
                .orderByAsc(PcStitchDetail::getSlipDate).list();
        List<PcStitchDetail> out = lambdaQuery().eq(PcStitchDetail::getLotNo, lotNo)
                .eq(PcStitchDetail::getSlipType, "O")
                .orderByAsc(PcStitchDetail::getSlipDate).list();

        List<StitchDetailDto> inDtos = BeanUtil.copyList(in, StitchDetailDto.class);
        List<StitchDetailDto> outDtos = BeanUtil.copyList(out, StitchDetailDto.class);
        for (StitchDetailDto inDto : inDtos) {
            inDto.setTtlQty(getQtyFieldValues(inDto));
        }
        for (StitchDetailDto outDto : outDtos) {
            outDto.setTtlQty(getQtyFieldValues(outDto));
        }
        LambdaQueryWrapper<PcLotHead> wrapperH = new LambdaQueryWrapper<PcLotHead>()
                .select(PcLotHead::getStyle, PcLotHead::getColor, PcLotHead::getDeliveryDate,
                        PcLotHead::getOrderQty, PcLotHead::getSurplusQty)
                .eq(PcLotHead::getLotNo, lotNo);
        /*获取并提取指令型体数据*/
        PcLotHead lotHead = lotHeadMapper.selectOne(wrapperH);
        /*判断数据是否存在*/
        if (lotHead == null){
            return ResponseInfo.error("无效指令", INPUT_ERROR.getCode());
        }
        Float aFloat = ((lotHead.getOrderQty()==null?0:lotHead.getOrderQty()) + (lotHead.getSurplusQty()==null?0:lotHead.getSurplusQty())); //整合为输出语句
        String qty = aFloat + "双（含预补" + lotHead.getSurplusQty() + "双)";
        Map<String, Object> style = new HashMap<>();
        style.put("style", lotHead.getStyle());
        style.put("color", lotHead.getColor());
        style.put("deliveryDate", lotHead.getDeliveryDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        style.put("qty", qty);
        /*获取并处理尺寸和订单数*/
        LambdaQueryWrapper<PcLotDetail> wrapperD = new LambdaQueryWrapper<PcLotDetail>()
                .eq(PcLotDetail::getLotNo, lotNo)
                .orderByAsc(PcLotDetail::getSeqNo);
        List<PcLotDetail> details = lotDetailMapper.selectList(wrapperD);
        List<Map<String, String>> size = new ArrayList<>();
        List<Map<String, Float>> sizeTotal = new ArrayList<>();
        if (ArrayUtils.isNoEmpyt(details)) {
            size = details
                    .stream().map(a -> {
                        Map<String, String> map = new HashMap<>();
                        long supQty = a.getSurplusQty() == null ? 0 : a.getSurplusQty().longValue();
                        map.put(a.getSizeNo(), a.getOrderQty().longValue() + "+" + supQty);
                        return map;
                    }).
                    collect(Collectors.toList());
            sizeTotal = details
                    .stream().map(a -> {
                        Map<String, Float> map = new HashMap<>();
                        float orderQty = Optional.ofNullable(a.getOrderQty()).orElse(0.0f);
                        float surplusQty = Optional.ofNullable(a.getSurplusQty()).orElse(0.0f);
                        map.put(a.getSizeNo(), orderQty + surplusQty);
                        return map;
                    }).collect(Collectors.toList());
        }
        /*整合数据并输出*/
        Map<String, Object> map = new HashMap<>();
        map.put("inDtos", inDtos);
        map.put("outDtos", outDtos);
        map.put("style", style);
        map.put("size", size);
        map.put("sizeTotal", sizeTotal);
        return ResponseInfo.ok(map);
    }

    /**
     * 反射求所有qty开头的数据之和
     * @param stitchDetailDto
     * @return
     */
    public static Float getQtyFieldValues(StitchDetailDto stitchDetailDto) {
        Field[] fields = stitchDetailDto.getClass().getDeclaredFields();
        Float sum = (float) 0;
        for (Field field : fields) {
            if (field.getName().startsWith("qty")) {
                field.setAccessible(true);
                try {
                    Float value = (Float) field.get(stitchDetailDto);
                    if (value != null) {
                        sum += value;
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return sum;
    }

    /*收发明细新增-新增*/
    @Override
    @Transactional
    public ResponseInfo stitchIOAdd(StitchIORequest request, Integer length) {
        //新增入库判断，如果该指令已被冻结，无法进行入库操作
        if (request.getSlipType().equals("I")) {
            if (pcStitchFrozenMapper.selectCount(new QueryWrapper<PcStitchFrozen>().eq("lot_no", request.getLotNo())) > 0) {
                return ResponseInfo.error("该指令已被冻结，无法进行入库操作！");
            }
        }
        
        
        /*判断是否有填写多余数据*/
        Field[] fields = request.getClass().getDeclaredFields();
        int i=length;
        for (Field field : fields) {
            if (field.getName().equals("qty"+i)){
                i++;
                field.setAccessible(true);
                try {
                    if(field.get(request)!=null){
                        throw new ServiceErrorException("超出范围限制");
                    }
                } catch (IllegalAccessException e) {
                    System.err.println("反射没有找到对应元素");
                }
            }
        }
        /*获取待写入数据*/
        PcStitchDetail detail = BeanUtil.copyBean(request, PcStitchDetail.class);
        detail.setSysDate(LocalDateTime.now());
        detail.setSysUser(UserIdThread.get().getUserName());
        detail.setUpdateDate(LocalDateTime.now());
        detail.setUpdateUser(UserIdThread.get().getUserName());
        detail.setCompanyId("BF");
        detail.setStkName("一部");        //不确定
        detail.setOutDept(0);
        detail.setSlipNo(redisService.slipNoCreatByTime("XM"));
        /*新增数据*/
        detailMapper.insert(detail);


        /*更新detailAttach数据*/
        List<PcCodeAndStitchDto> codeAndStitchList = assembleData(request);
        if (ObjectUtils.isNotEmpty(codeAndStitchList)) {
            // 提取所有需要的 qtyFlag
            List<String> qtyList = codeAndStitchList.stream()
                    .map(PcCodeAndStitchDto::getQtyFlag)
                    .collect(Collectors.toList());
            // 根据qty去查询鞋码
            PcCodeRequest pcCodeRequest = new PcCodeRequest();
            pcCodeRequest.setCompanyId(UserIdThread.get().getCompanyId());
            pcCodeRequest.setLotNo(request.getLotNo());
            pcCodeRequest.setQtyFlagList(qtyList);
            List<PcLotDetailDto2> codeDetailList = pcLotHeadMapper.getCodeDetails5(pcCodeRequest);
            // 使用 Map 提高查找效率》》
            Map<String, PcLotDetailDto2> detailMap = codeDetailList.stream()
                    .collect(Collectors.toMap(PcLotDetailDto2::getQtyFlag, dto -> dto));
            // 更新 codeAndStitchList 中的对象
            List<PcStitchDetailAttach> attachList = new ArrayList<>();
            for (PcCodeAndStitchDto pcCodeAndStitchDto : codeAndStitchList) {
                PcStitchDetailAttach detailAttach = new PcStitchDetailAttach();
                BeanUtil.copyProperties(pcCodeAndStitchDto, detailAttach);
                PcLotDetailDto2 detailDto2 = detailMap.get(pcCodeAndStitchDto.getQtyFlag());
                if (detailDto2 != null) {
                    //pcCodeAndStitchDto.setSeqNo(detailDto2.getSeqNo());
                    //pcCodeAndStitchDto.setSizeNo(detailDto2.getSizeNo());
                    detailAttach.setSeqNo(Integer.valueOf(detailDto2.getSeqNo()));
                    detailAttach.setSizeNo(detailDto2.getSizeNo());
                }
                detailAttach.setCompanyId(UserIdThread.get().getCompanyId());
                detailAttach.setUpdateUser(UserIdThread.get().getUserName());
                detailAttach.setSysUser(UserIdThread.get().getUserName());
                detailAttach.setSysDate(LocalDateTime.now());
                detailAttach.setUpdateDate(LocalDateTime.now());
                detailAttach.setSlipNo(detail.getSlipNo());
                detailAttach.setStkName("一部");
                detailAttach.setSlipType(detail.getSlipType());
                detailAttach.setDeptName(detail.getDeptName());
                attachList.add(detailAttach);
            }

            //根据slipno查询，如果不存在就新增；如果存在，就删掉slipNo的，把刚刚的数据新增
            List<PcStitchDetailAttach> detailAttachs = detailAttachMapper.queryStitchDetailAttach2(detail.getSlipNo());
            int count2 = 0;
            int count3 = 0;
            if (ObjectUtils.isEmpty(detailAttachs)){
                count2 = detailAttachMapper.batchInsert(attachList); //不存在就新增
            }else{
                LambdaQueryWrapper<PcStitchDetailAttach> wrapper2=new LambdaQueryWrapper<PcStitchDetailAttach>()
                        .eq(PcStitchDetailAttach::getSlipNo,detail.getSlipNo());
                count3 = attachMapper.delete(wrapper2);
                count2 = detailAttachMapper.batchInsert(attachList);
            }
        }

        return ResponseInfo.ok();
    }

    /*收发明细修改-更新*/
    @Override
    @Transactional
    public ResponseInfo stitchIOUp(StitchIORequest request) {
        
        //上锁
        String companyId = UserIdThread.get().getCompanyId();
        String lockKey = "StitchScanOld:" + companyId + ":" + request.getSlipNo()  ;
        String lockValue = UUID.randomUUID().toString();
        Boolean isLocked = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 5, TimeUnit.SECONDS);
        if (!isLocked) {
            throw new ServiceErrorException("系统处理数据中,请稍后重试!");
        }
        try {

        /*判断是否为本人数据*/
        LambdaQueryWrapper<PcStitchDetail> wrapper=new LambdaQueryWrapper<PcStitchDetail>()
                .eq(PcStitchDetail::getSlipNo,request.getSlipNo());
        PcStitchDetail detail = detailMapper.selectOne(wrapper);

        //新增入库判断，如果该指令已被冻结，无法进行入库操作
        if (detail.getSlipType().equals("I")) {
            if (pcStitchFrozenMapper.selectCount(new QueryWrapper<PcStitchFrozen>().eq("lot_no", request.getLotNo())) > 0) {
                return ResponseInfo.error("该指令已被冻结，无法进行入库操作！");
            }
        }

        //使用权限
        //1.只能给面材仓管（BFCC05：面材仓管）和冯经理（CC01：IE经理-步峰）可以修改所有人的数据
         //2.自己新增的数据只能自己修改
         String userId = UserIdThread.get().getUserId();
         SdUser user = sdUserMapper.getUserByUserId(userId);
         String posId = user.getPosId();
         if(posId == null || posId.equals("")){
             if (detail.getSysUser()!=null && !detail.getSysUser().equals(UserIdThread.get().getUserName())){
                 throw new ServiceErrorException("非本人数据不能修改");
             }
         }else{
             if(!posId.equals("BFCC05") && !posId.equals("CC01")){
                 if (detail.getSysUser()!=null &&!detail.getSysUser().equals(UserIdThread.get().getUserName())){
                     throw new ServiceErrorException("非本人数据不能修改");
                 }
             }
         }


        //在入库，更新数量要看是否报账了没有，如果报账了，那么更新数量不能小于原来的数量
        if(detail != null && detail.getSlipType() != null && detail.getSlipType().equals("I") ){
            //获得改指令+部门+出入库类型+入库时间 报账的最大工序
            PcStitchDetailAttachRequest prodSeqRequest = new PcStitchDetailAttachRequest();
            BeanUtils.copyProperties(detail,prodSeqRequest);
            prodSeqRequest.setSlipDateStart(String.valueOf(detail.getSlipDate()));
            prodSeqRequest.setSlipDateEnd(String.valueOf(detail.getSlipDate()));
            List<InventoryPaymentDetailsDto> prodSeqList = sewingProductionDataMapper.getCostDetailsList(companyId,prodSeqRequest);
            if(ObjectUtils.isNotEmpty(prodSeqList)){
                InventoryPaymentDetailsDto prodSeqDto = prodSeqList.get(0);
                if (prodSeqDto != null) {
                    if (prodSeqDto.getMaxQty() != null) {
                        //已经报账的用量
                        Float oldQtyCount = prodSeqDto.getMaxQty().floatValue(); //某道工序用的最大的值
                        //现在更新的数量：
                        Float newQtyCount = safeGetQty(request.getQty1()) + safeGetQty(request.getQty2()) + safeGetQty(request.getQty3()) + safeGetQty(request.getQty4())
                                + safeGetQty(request.getQty5()) + safeGetQty(request.getQty6()) + safeGetQty(request.getQty7()) + safeGetQty(request.getQty8()) + safeGetQty(request.getQty9())
                                + safeGetQty(request.getQty10()) + safeGetQty(request.getQty11()) + safeGetQty(request.getQty12()) + safeGetQty(request.getQty13()) + safeGetQty(request.getQty14())
                                + safeGetQty(request.getQty15()) + safeGetQty(request.getQty16()) + safeGetQty(request.getQty17()) + safeGetQty(request.getQty18()) + safeGetQty(request.getQty19())
                                + safeGetQty(request.getQty20()) + safeGetQty(request.getQty21()) + safeGetQty(request.getQty22()) + safeGetQty(request.getQty23()) + safeGetQty(request.getQty24())
                                + safeGetQty(request.getQty25()) + safeGetQty(request.getQty26());

                        boolean isFalg = oldQtyCount != null && newQtyCount != null && newQtyCount < oldQtyCount;
                        if(isFalg){
                            throw new ServiceErrorException("该条数据有报账，不能减少入库数量，请先取消报账再做更新！\n" );
                        }
                    }
                }
            }
        }

        /*更新数据*/
        /*更新detail数据*/
        PcStitchDetail detailU = BeanUtil.copyBean(request, PcStitchDetail.class);
        detailU.setUpdateDate(LocalDateTime.now());
        detailU.setUpdateUser(UserIdThread.get().getUserName());
        int count1 = detailMapper.update(detailU,wrapper);
        //查询当前修改完后的部门数据，因为前端无法在修改用量时发送部门信息
       LambdaQueryWrapper<PcStitchDetail> wrapper3=new LambdaQueryWrapper<PcStitchDetail>()
               .eq(PcStitchDetail::getSlipNo,request.getSlipNo());
       PcStitchDetail detail3 = detailMapper.selectOne(wrapper3);

        /*更新detailAttach数据*/
        List<PcCodeAndStitchDto> codeAndStitchList = assembleData(request);
        if (ObjectUtils.isEmpty(codeAndStitchList)) {
            throw new ServiceErrorException("没有数据可更新");
        }
        // 提取所有需要的 qtyFlag
        List<String> qtyList = codeAndStitchList.stream()
                .map(PcCodeAndStitchDto::getQtyFlag)
                .collect(Collectors.toList());
        // 根据qty去查询鞋码
        PcCodeRequest pcCodeRequest = new PcCodeRequest();
        pcCodeRequest.setCompanyId(UserIdThread.get().getCompanyId());
        pcCodeRequest.setLotNo(request.getLotNo());
        pcCodeRequest.setQtyFlagList(qtyList);
        List<PcLotDetailDto2> codeDetailList = pcLotHeadMapper.getCodeDetails5(pcCodeRequest);
        // 使用 Map 提高查找效率》》
        Map<String, PcLotDetailDto2> detailMap = codeDetailList.stream()
                .collect(Collectors.toMap(PcLotDetailDto2::getQtyFlag, dto -> dto));
        // 更新 codeAndStitchList 中的对象
        List<PcStitchDetailAttach> attachList = new ArrayList<>();
        for (PcCodeAndStitchDto pcCodeAndStitchDto : codeAndStitchList) {
            PcStitchDetailAttach detailAttach = new PcStitchDetailAttach();
            BeanUtil.copyProperties(pcCodeAndStitchDto, detailAttach);
            PcLotDetailDto2 detailDto2 = detailMap.get(pcCodeAndStitchDto.getQtyFlag());
            if (detailDto2 != null) {
                //pcCodeAndStitchDto.setSeqNo(detailDto2.getSeqNo());
                //pcCodeAndStitchDto.setSizeNo(detailDto2.getSizeNo());
                detailAttach.setSeqNo(Integer.valueOf(detailDto2.getSeqNo()));
                detailAttach.setSizeNo(detailDto2.getSizeNo());
            }
            detailAttach.setCompanyId(UserIdThread.get().getCompanyId());
            detailAttach.setUpdateUser(UserIdThread.get().getUserName());
            detailAttach.setSysUser(UserIdThread.get().getUserName());
            detailAttach.setSysDate(LocalDateTime.now());
            detailAttach.setUpdateDate(LocalDateTime.now());
            detailAttach.setSlipNo(request.getSlipNo());
            detailAttach.setStkName("一部");
            detailAttach.setSlipType(detail.getSlipType());
            detailAttach.setDeptNo(detail3.getDeptNo()); //部门信息要取更新后的信息
            detailAttach.setDeptName(detail3.getDeptName());
            attachList.add(detailAttach);
        }

        //根据slipno查询，如果不存在就新增；如果存在，就删掉slipNo的，把刚刚的数据新增
        List<PcStitchDetailAttach> detailAttachs = detailAttachMapper.queryStitchDetailAttach2(detail.getSlipNo());
        int count2 = 0;
        int count3 = 0;
        if (ObjectUtils.isEmpty(detailAttachs)){
            try{
             count2 = detailAttachMapper.batchInsert(attachList); //不存在就新增
            }catch (UncategorizedSQLException e) {
                handleDatabaseException(e, "新增 PC_STITCH_DETAIL_ATTACH失败");
            }catch (Exception e) {
                log.error("新增 PC_STITCH_DETAIL_ATTACH失败: ", e);
                throw new ServiceErrorException("新增 PC_STITCH_DETAIL_ATTACH失败{}"); // 或者根据需要抛出其他异常
            }

        }else{
            LambdaQueryWrapper<PcStitchDetailAttach> wrapper2=new LambdaQueryWrapper<PcStitchDetailAttach>()
                    .eq(PcStitchDetailAttach::getSlipNo,detail.getSlipNo());
            count3 = attachMapper.delete(wrapper2);
            try{
            count2 = detailAttachMapper.batchInsert(attachList);
        }catch (UncategorizedSQLException e) {
                handleDatabaseException(e, "新增 PC_STITCH_DETAIL_ATTACH失败");
            }catch (Exception e) {
                log.error("新增 PC_STITCH_DETAIL_ATTACH失败: ", e);
                throw new ServiceErrorException("新增 PC_STITCH_DETAIL_ATTACH失败{}"); // 或者根据需要抛出其他异常
            }
        }
        if (count1 > 0 && count2 > 0 ) {
            return ResponseInfo.ok();
        }else{
            throw new ServiceErrorException("失败");
        }


    }finally {
            // 检查并释放锁
            String existingValue = (String) redisTemplate.opsForValue().get(lockKey);
            if (lockValue.equals(existingValue)) {
                redisTemplate.delete(lockKey); // 释放锁
            }
        }
    }


    public List<PcCodeAndStitchDto> assembleData(StitchIORequest request) {
        //组装数据容器
        List<PcCodeAndStitchDto> codeAndStitchList = new ArrayList<>();
        // 获取所有声明的字段
        Field[] fields = request.getClass().getDeclaredFields();
        // 遍历所有字段，提取 qty 字段及其值
        for (Field field : fields) {
            if (field.getName().startsWith("qty") && field.getType() == Float.class) {
                field.setAccessible(true);
                try {
                    String fieldName = field.getName();
                    Float value = (Float) field.get(request);

                    if (value != null) {
                        PcCodeAndStitchDto codeAndStitchDto = new PcCodeAndStitchDto();
                        BeanUtil.copyProperties(request, codeAndStitchDto);
                        codeAndStitchDto.setQtyFlag(fieldName);
                        codeAndStitchDto.setQty(value);
                        codeAndStitchList.add(codeAndStitchDto);
                    }
                } catch (IllegalAccessException e) {
                    // 更好的异常处理，例如记录详细日志
                    throw new RuntimeException("反射访问字段失败: " + field.getName(), e);
                }
            }
        }
        return codeAndStitchList;
    }

    /*收发明细删除-删除*/
    @Override
    @Transactional
    public ResponseInfo stitchIODetail(String slipNo) {
        
        /*判断是否为本人数据*/
        LambdaQueryWrapper<PcStitchDetail> wrapper=new LambdaQueryWrapper<PcStitchDetail>()
                .eq(PcStitchDetail::getSlipNo,slipNo);
        LambdaQueryWrapper<PcStitchDetailAttach> wrapper2=new LambdaQueryWrapper<PcStitchDetailAttach>()
                .eq(PcStitchDetailAttach::getSlipNo,slipNo);
        PcStitchDetail detail = detailMapper.selectOne(wrapper);

        if (detail.getSlipType().equals("I")) {
            if (pcStitchFrozenMapper.selectCount(new QueryWrapper<PcStitchFrozen>().eq("lot_no", detail.getLotNo())) > 0) {
                return ResponseInfo.error("该指令已被冻结，无法进行入库操作！");
            }
        }

        //使用权限
        //1.只能给面材仓管（BFCC05：面材仓管）和冯经理（CC01：IE经理-步峰）可以修改所有人的数据
        //2.自己新增的数据只能自己修改
        String userId = UserIdThread.get().getUserId();
        SdUser user = sdUserMapper.getUserByUserId(userId);
        String posId = user.getPosId();
        if(posId == null || posId.equals("")){
            if (detail.getSysUser()!=null && !detail.getSysUser().equals(UserIdThread.get().getUserName())){
                throw new ServiceErrorException("非本人数据不能修改");
            }
        }else{
            if(!posId.equals("BFCC05") && !posId.equals("CC01")){
                if (detail.getSysUser()!=null &&!detail.getSysUser().equals(UserIdThread.get().getUserName())){
                    throw new ServiceErrorException("非本人数据不能修改");
                }
            }
        }

        //在入库，删除判断是否报账
        if(detail != null && detail.getSlipType() != null && detail.getSlipType().equals("I") ){
            //删除的时候要看该指令+部门+出入库类型+入库时间 有没有报账单，如果有就不能删除
            PcStitchProdDetailRequest prodRequest = new PcStitchProdDetailRequest();
            BeanUtils.copyProperties(detail,prodRequest);
            prodRequest.setStartDate(String.valueOf(detail.getSlipDate()));
            prodRequest.setEndDate(String.valueOf(detail.getSlipDate()));
            List<PcStitchProdDetailDto2> prodList = pcStitchProdDetailMapper.getPcStitchProdDetailList(prodRequest);
            if(ObjectUtils.isNotEmpty(prodList)){
                String masg = "指令数据：" +  detail.getLotNo()+ ",入库时间：" + detail.getSlipDate()+ "，部门：" +detail.getDeptName();
                throw new ServiceErrorException("该条数据有报账，不能删除，请先取消报账再删除！\n" );
            }
        }
        
        /*删除数据*/
        detailMapper.delete(wrapper);
        attachMapper.delete(wrapper2);
        return ResponseInfo.ok();
    }

    /**
     * 查询收发明细
     * @param request
     * @return
     */
    @Override
    @AutoPageAop
    public ResponseInfo getStitchDetail(StitchStockRequest request) {
        String companyId = UserIdThread.get().getCompanyId();
        request.setCompanyId(companyId);
        List<PcStitchStockDetailDto> list = detailMapper.getStitchDetail(request);

        //统计收发料总数量
        PcStitchStockDetailDto countDto = detailMapper.getStitchDetailCount(request);

        PageInfo pageInfo = new PageInfo(list);
        HashMap map = new HashMap<>();
        map.put("list", list);
        map.put("countDto", countDto);
        map.put("total", pageInfo.getTotal());
        return ResponseInfo.ok(map);
    }

    /**
     * 查询收发号码明细
     * @param request
     * @return
     */
    @Override
    public ResponseInfo getStitchSizeDetail(StitchStockRequest request) {
        String companyId = UserIdThread.get().getCompanyId();
        request.setCompanyId(companyId);
        List<PcStitchDetailDto> list = detailMapper.getStitchSizeDetail(request);

        //统计号码收发料总数量
        //PcStitchDetailDto countDto = detailMapper.getStitchSizeDetail(request);

        HashMap map = new HashMap<>();
        map.put("list", list);
        //map.put("countDto", countDto);
        return ResponseInfo.ok(map);
    }
    /**
     * 查询收发号码明细导出
     * @param request
     * @return
     */
    @Override
    public void getStitchDetailExport(StitchStockRequest request,HttpServletResponse response) throws IOException
    {
        String companyId = UserIdThread.get().getCompanyId();
        request.setCompanyId(companyId);

        List<PcStitchStockDetailDto> list = detailMapper.getStitchDetail(request);
        for (PcStitchStockDetailDto item : list) {
            item.setSlipType("I".equals(item.getSlipType()) ? "收料" : "发料");
        }
        HashMap map = new HashMap<>();
        List<Map<String, Object>> tempList = list.stream()
                .map(item -> {
                    Map<String, Object> mapItem = new HashMap<>();
                    String dateOnly = item.getDate().toString().replace("T00:00", "");
                    mapItem.put("slipType", item.getSlipType());
                    mapItem.put("deptName", item.getDeptName());
                    mapItem.put("qty", item.getQty());
                    mapItem.put("sysUser", item.getSysUser());
                    mapItem.put("lotNo", item.getLotNo());
                    mapItem.put("dates",dateOnly);
                    mapItem.put("style", item.getStyle());
                    mapItem.put("orderQty", item.getOrderQty());
                    mapItem.put("deptNo", item.getDeptNo());
                    return mapItem;
                })
                .collect(Collectors.toList());
        map.put("list", tempList);
        TemplateExportParams templateParams = new TemplateExportParams("templates/鞋面收发料明细模板.xlsx", true);
        templateParams.setColForEach(true);
        String fileName = "鞋面收发料_" + DateUtils.dateTimeNow() + ".xlsx";

        try {
            ExcelPoiUtils.writeExcelList1(response,  map, templateParams);
            ExcelUtils.setResponseZF(response, fileName);
        }
        catch (UnsupportedEncodingException e) {
            log.error("导出失败, 错误信息: {}", e.getMessage());
            throw new ServiceErrorException("导出失败!");
        }
    }

    /**
     * 给某些人单独权限可以修改和删除所有数据，不受时间和本人数据限制
     * falg ；1:查id，2查用户
     */
    private boolean toAuthority2(String userId) {
        List<String> userIdList = new ArrayList<>();
        userIdList.add("WSH");
        return userIdList.contains(userId);
    }

    /**
     * 给某些职位的单独权限可以修改和删除所有数据，不受时间和本人数据限制
     * 只能给面材仓管（BFCC05：面材仓管）和冯经理（CC01：IE经理-步峰）可以修改所有人的数据
     * ZQ01：咨询顾问 暂时也不给权限
     */
    private boolean toAuthority(String posId) {
        List<String> posIdList = new ArrayList<>();
        posIdList.add("BFCC05");
        posIdList.add("CC01");
        return posIdList.contains(posId);
    }


    private float safeGetQty(Float qty) {
        return qty != null ? qty.floatValue() : 0.0f;
    }

        /**
         * 抓取数据库触发器的自定义的异常提示
         * @param e
         * @param errorMessagePrefix
         */
        private void handleDatabaseException(UncategorizedSQLException e, String errorMessagePrefix) {
            Throwable cause = e.getCause();
            if (cause instanceof SQLException && "45000".equals(((SQLException) cause).getSQLState())) {
                String errorMessage = cause.getMessage();
                log.error(errorMessagePrefix + ": " + errorMessage);
                throw new ServiceErrorException(errorMessage);
            } else {
                log.error("数据库操作异常: ", e);
                throw e; // 或者根据需要抛出其他异常
            }
        }
}
